package com.piece.core.web.util;

import com.piece.core.framework.enums.ContentType;
import com.piece.core.framework.exception.ServerException;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.springframework.http.HttpStatus;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * WebService工具类
 */
public class WebServiceUtil {

    /**
     * 调用xFire接口
     *
     * @param url    请求地址
     * @param method 请求方法
     * @param params 请求参数
     */
    public static final Object xFireInvoke(String url, String method, Object... params) {
        try {
            org.codehaus.xfire.client.Client client = new org.codehaus.xfire.client.Client(new URL(url + "?wsdl"));
            return client.invoke(method, params);
        } catch (Exception e) {
            throw new ServerException(e.getMessage());
        }
    }

    /**
     * 调用CXF接口
     *
     * @param url    请求地址
     * @param method 请求方法
     * @param params 请求参数
     */
    public static final Object cxfInvoke(String url, String method, Object... params) {
        try {
            JaxWsDynamicClientFactory jaxWsDynamicClientFactory = JaxWsDynamicClientFactory.newInstance();
            org.apache.cxf.endpoint.Client client = jaxWsDynamicClientFactory.createClient(url);
            return client.invoke(method, params);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 调用SOAP接口
     *
     * @param url       请求地址
     * @param namespace 命名空间
     * @param method    请求方法
     * @param timeout   连接超时时间
     * @param soTimeout 响应超时时间
     * @param bean      请求参数对象
     */
    public static final Object soapInvoke(String url, String namespace, String method, int timeout, int soTimeout, Object bean) {
        try {
            String parameter = objectToXml(bean);
            PostMethod postMethod = new PostMethod(url + "?wsdl");
            String soapRequestData = buildRequestData(namespace, method, parameter);

            HttpClient httpClient = new HttpClient();
            // 设置连接超时
            httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(timeout);
            // 设置读取时间超时
            httpClient.getHttpConnectionManager().getParams().setSoTimeout(soTimeout);
            byte[] bytes = soapRequestData.getBytes("utf-8");
            InputStream inputStream = new ByteArrayInputStream(bytes, 0, bytes.length);
            RequestEntity requestEntity = new InputStreamRequestEntity(inputStream, bytes.length, ContentType.SOAP.toString(StandardCharsets.UTF_8));
            // 设置请求头部
            postMethod.setRequestHeader("SOAPAction", "");
            // 设置请求体
            postMethod.setRequestEntity(requestEntity);

            int status = httpClient.executeMethod(postMethod);
            String soapResponseData = postMethod.getResponseBodyAsString();
            if (status == HttpStatus.OK.value()) {
                return xmlToObject(soapResponseData, bean.getClass());
            } else {
                return null;
            }
        } catch (Exception e) {
            throw new ServerException(e.getMessage());
        }
    }

    /**
     * 组装请求报文
     */
    private static String buildRequestData(String namespace, String method, String parameter) {
        StringBuffer soapRequestData = new StringBuffer();
        soapRequestData.append("<soapenv:Envelope " +
                "xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
                "xmlns:ser=\"" + namespace + "\">");
        soapRequestData.append("<soapenv:Header/>");
        soapRequestData.append("<soapenv:Body>");
        soapRequestData.append("<ser:" + method + ">");
        soapRequestData.append(parameter);
        soapRequestData.append("</ser:" + method + ">");
        soapRequestData.append("</soapenv:Body>");
        soapRequestData.append("</soapenv:Body>");
        return soapRequestData.toString();
    }

    private static String objectToXml(Object obj) {
        XStream xStream = new XStream(new DomDriver());
        xStream.alias(obj.getClass().getSimpleName(), obj.getClass());
        String xml = xStream.toXML(obj);
        return xml.replaceAll("&quot;", "\"");
    }

    private static Object xmlToObject(String xml, Class obj, String... str) {
        XStream xStream = new XStream(new DomDriver());
        if (null != str && str.length > 0) {
            xStream.alias(str[0], List.class);
        }
        xml = xml.substring(xml.indexOf("<" + obj.getSimpleName() + ">"), xml.lastIndexOf("</" + obj.getSimpleName() + ">"));
        xml += "</" + obj.getSimpleName() + ">";
        xStream.alias(obj.getSimpleName(), obj);
        return xStream.fromXML(xml);
    }
}
